package cn.tedu.store.order.webapi.filter;

import cn.tedu.store.commons.web.JsonResult;
import cn.tedu.store.commons.web.ServiceCode;
import cn.tedu.store.order.webapi.security.LoginPrincipal;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@Slf4j
@Component
public class JwtAuthorizationFilter extends OncePerRequestFilter {

    public static final Integer JWT_MIN_LENGTH = 100;

    @Value("${hanccc.jwt.secret-key}")
    String secretKey;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        //清除原有数据
        SecurityContextHolder.clearContext();

        String jwt = request.getHeader("Authorization");

        log.debug("接收到的jwt: "+jwt);

        if(!StringUtils.hasText(jwt) || jwt.length() < JWT_MIN_LENGTH){
            log.warn("未获取到有效的jwt数据,直接放行");
            filterChain.doFilter(request,response);
            return;
        }
        log.debug("尝试解析接收到的jwt数据...");

        response.setContentType("application/json; charset=utf-8");

        Claims claims = null;
        try {
            claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
        }catch (SignatureException e) {
            String message = "非法访问!";
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_SIGNATURE,message);
            responseJson(jsonResult,response);
            return;
        }catch (MalformedJwtException e){
            String message = "非法访问!";
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_MALFORMED,message);
            responseJson(jsonResult,response);
            return;
        }catch (ExpiredJwtException e){
            String message = "登录过期,请重新登录!";
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_EXPIRED,message);
            responseJson(jsonResult,response);
            return;
        }catch (Throwable e){
            String message = "服务器忙,请稍后再试!";
            JsonResult<Void> jsonResult = JsonResult.fail(ServiceCode.ERR_UNKNOWN,message);
            responseJson(jsonResult,response);
            return;
        }
        Long id = claims.get("id",Long.class);
        String username = claims.get("username",String.class);
        String authoritiesJsonString = claims.get("authorities",String.class);
        log.debug("解析得到数据id:{}",id);
        log.debug("解析得到数据username:{}",username);
        log.debug("解析得到数据authorities1:{}",authoritiesJsonString);
        log.debug("解析得到数据authorities1类型:{}",authoritiesJsonString.getClass().getName());
        //log.debug("解析得到数据authorities1的元素类型:{}",((ArrayList)authorities1).get(0).getClass().getName());
        //生成验证信息
        List<SimpleGrantedAuthority> authorities =
                JSON.parseArray(authoritiesJsonString, SimpleGrantedAuthority.class);

        LoginPrincipal loginPrincipal = new LoginPrincipal();
        loginPrincipal.setId(id);
        loginPrincipal.setUsername(username);
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                loginPrincipal,null,authorities
        );
        //将认证信息存入securityContext
        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authentication);

        filterChain.doFilter(request,response);
    }
    private void responseJson(JsonResult<Void> jsonResult,HttpServletResponse response) throws IOException {
        String jsonResultString = JSON.toJSONString(jsonResult);
        PrintWriter writer = response.getWriter();
        writer.println(jsonResultString);
        writer.close();
    }
}
